#ifndef GX_FR_RENDERER_H
#define GX_FR_RENDERER_H

#include "Material.h"
#include "BSP_Scene.h"
#include "Lightmap.h"
#include "LibGL/GxGLCamera.h"

namespace FinalRendering
{
	namespace Engine
	{
		class HDR_Processor : public Object
		{
		private:
			RefPtr<Lightmap> colorHDR, bloom, colorHalf, colorQuad, colorOct, bloomBlur;
			RefPtr<Lightmap> brightnessEval;
			RefPtr<RenderBuffer> rbColor;
			RefPtr<FrameBufferObject> fboHDR, fboBloom, fboHalf, fboQuad, fboOct, fboBlur;
			RefPtr<FrameBufferObject> fboBrightness;
			RefPtr<Program> progTone, progBloom, progDownSample, progBlurX, progBlurY;
			Array<float> pixBuf;
			int width, height;
			float brightness, lastBrightness;
			int locToneSrc, locToneBrightness, locToneBloom;
			int locBloomSrc, locBloomBrightness;
			int locDSSrc, locDSdx, locDSdy;
			int locBlurXSrc, locBlurXD, locBlurYSrc, locBlurYD;
			float EvalBrightness(int id);
			void DownSample();
			void Blur();
		public:
			float AutoExposureRate;
			HDR_Processor(int w, int h);
			void BeginRendering();
			void EndRendering(float dTime);
		};

		struct SurfaceRenderCommand
		{
			Material * mat;
			Surface * surf;
			bool operator == (const SurfaceRenderCommand & cmd);
			bool operator < (const SurfaceRenderCommand & cmd);
		};

		class Renderer : public Object
		{
		private:
			static const int MaxReflectionLevel = 1;
			RefPtr<FrameBufferObject> reflectionFrameBuffers[MaxReflectionLevel];
			RefPtr<RenderBuffer> reflectionRenderBuffer;
			RefPtr<Lightmap> reflectionTextures[MaxReflectionLevel];
			int width, height;
			Plane reflectPlane;
		private:
			int nodeID;
			UInt vbo;
			Scene * scene;
			RefPtr<HDR_Processor> hdr;
			RefPtr<ProgramPool> programPool;
			RefPtr<Material> generalMaterial;
			RefPtr<LightmapSolution> solution;
			GxRendering::Camera * camera;
			Array<RefPtr<Material>> materials;
			Array<SurfaceRenderCommand, true> renderQueue;
			void Material_OnSetClientUniform(Material * mat, Object * target, const String & uniName, int loc);
			void DrawQueue(int recurseLevel = 0);
		public:
			
			bool WireFrame;
			bool PvsCulling;
			void SetScene(Scene * _scene);
			void Render(float dTime);
			void DrawLeaf(int id);
			void DrawPortal(int id);
			void SetNode(int node_id);
			void LoadLightmapSolution(LightmapSolution * _solution);
			void DebugDrawLightmap(int id);
			void SetResolution(int w, int h);
			Material * GetMaterial(int id);
			void SetCamera(GxRendering::Camera * cam);
			Renderer(int w, int h);
			~Renderer();
		};
	}
}

#endif